package cn.js.tech;

import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Hello world!
 */
@Slf4j
public class CrackerAnalysis {


    static final String licence = "389333BCF0FD8C355C3CA5EB80026320";
    static final String licence_key = "bCmHkYKZo69zuKeQN89V2BaRJe2MSfb5dxhp/VQq6ee3tLeDnZCg1vek81lzkPD9Y2bFZSJeAgeXjADsmg1iJJb/mOQgo/d5IEdFHNqlEwZZQ3VnPgtBCzzVuOpR2sgxVgtCQLp8MOOIJZ8CAKtIiC11Nn1BzUt3vGKgOlnUYgE=";

    static final String privateKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxHEhhLwdDhZ57SlLt/5JWFeGRy4r+NKgbA0VwkCXs7p0w1bNgKlRJOzUfjg6kMi4ygkVNNPWrXIhcdMniTbcHmawawLTa3cRM1jNdG0xg808KKNVdDilFHOFQz8AF6cvLDpsWkqzmoe2+64v0zlWbp5EpYxMMRxOwSMVKxLB8BwIDAQAB";

    public static void main(String[] args) throws Exception {

        String identifyStr = getIdentify();
        System.out.println("识别码：");
        System.out.println(identifyStr);
log.info("测试日志");
        String identifyMd5 = md5(identifyStr);
        String SN = identifyMd5.toUpperCase();
        System.out.println("SN码：");
        System.out.println(SN);

//        String decryptedString = decryptRsa("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxHEhhLwdDhZ57SlLt/5JWFeGRy4r+NKgbA0VwkCXs7p0w1bNgKlRJOzUfjg6kMi4ygkVNNPWrXIhcdMniTbcHmawawLTa3cRM1jNdG0xg808KKNVdDilFHOFQz8AF6cvLDpsWkqzmoe2+64v0zlWbp5EpYxMMRxOwSMVKxLB8BwIDAQAB", "qeRqo/rXGiHD4rcSAJ07ZlSIT8mKBltrDmOq/XgOoadOr28QK+fSIq/hAwDP3AKQv5eWMHQ+1iHxluJY30jVoyW6UK+2RqCrTx5cDF45/gP+8y5Les0JJUy0tQ7QvNLgRGiM6S4lSyBtBK7TQwJA04pyorNNN0jjaH42k2wP6Wk=");
//        System.out.println(decryptedString);

        String decryptedLicenceKey = decryptRsa(privateKey, licence_key);
        System.out.println("licence.key解密：");
        System.out.println(decryptedLicenceKey);


        String[] decryptedStrings = decryptedLicenceKey.split("\\|");

        String snStr = decryptRsa("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxHEhhLwdDhZ57SlLt/5JWFeGRy4r+NKgbA0VwkCXs7p0w1bNgKlRJOzUfjg6kMi4ygkVNNPWrXIhcdMniTbcHmawawLTa3cRM1jNdG0xg808KKNVdDilFHOFQz8AF6cvLDpsWkqzmoe2+64v0zlWbp5EpYxMMRxOwSMVKxLB8BwIDAQAB", "Hpe2Y2xbC9O5/UTpTy7vo1b/uVB2TlRpshb1pTsOCdR+DJbrjCktyA37LCrUXaeMioqwmwkZqlg8cQKErWjhUKPjDN45o7wcCnYxmToc7rds9LTWGRszoTdzanz7LiIm0b6Nn7yRMZMKnkwYga+PIT9gqUsI0CLscU8XKN7HZcs=");
        System.out.println("SN字符串：");
        System.out.println(snStr);

        String notMatchStr = decryptAes("TUgngENtt0uj2sfp6FlddG6W+fR2H8SL/Bk3/mFMjsORiafKdahlaco3evteBTZep5wJ8zzd3DkenasNDj/UQWMT5RaC+kpbKY+LooViJqM=", "0923");
        System.out.println("注册码不匹配字符串：");
        System.out.println(notMatchStr);

        String invalidStr = decryptAes("pguwZ9Udf4EpTzZeMYj++bVC3UzmObMCvAROyoO3brTiYVLxdEj+Uvd8VSyafWWjvqu1Gkh8Lgnw+K/bLwJUXw==", "092311");
        System.out.println("注册码无效字符串：");
        System.out.println(invalidStr);

        if (decryptedStrings[1].equals(SN)) {
            System.out.println("！！！SN匹配！！！");
        }

        //Exception
        System.out.println(snStr + SN);
        System.err.println(notMatchStr);


        //Exception
        System.out.println(snStr + SN);
        System.err.println(invalidStr);


        //FA814E8C4675AD8615D20A39100BB22AA1225_ FA814E8C4675AD8615D20A39100BB22A_ 1Combating Piracy
        //3F2C7849BB3A94C70B15409313278928
        String PiracyStr = identifyMd5.toUpperCase() + decryptedStrings[0] + "_ " + decryptedStrings[1] + "_ " + decryptedStrings[2] + "Combating Piracy";
        System.out.println("打击盗版字符串：");
        System.out.println(PiracyStr);
        String licenceStr = md5(PiracyStr).toUpperCase();
        System.out.println("注册码：");
        System.out.println(licenceStr);

        String jeecglicStr = decryptRsa("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxHEhhLwdDhZ57SlLt/5JWFeGRy4r+NKgbA0VwkCXs7p0w1bNgKlRJOzUfjg6kMi4ygkVNNPWrXIhcdMniTbcHmawawLTa3cRM1jNdG0xg808KKNVdDilFHOFQz8AF6cvLDpsWkqzmoe2+64v0zlWbp5EpYxMMRxOwSMVKxLB8BwIDAQAB", "U5VwTnDVppT0puHtkE/Uj3/K4JUu+7l0Qa2Q0BRGCucOyujbPZYFmQEu76sx0fxnXA4OK8TgoaUXWaU3lnWm3skMMel6Q/jRJn8LzsP4FE7Q/g4mTJYU3WqxxRCzRNtQqgtFq/St6ujClGeuaxwIrWUB5HqVbaRoDJoRZ5ecl+0=");
        System.out.println(jeecglicStr);

        String licenseIsError = decryptAes("kOzlPKX8Es8/FwQdXX60NZDs5Tyl/BLPPxcEHV1+tDWQ7OU8pfwSzz8XBB1dfrQ1iN5zqKZaPYep6qn8X+n2QLKRXOKp2vFQjVEFS7T75CGCnTDPggguLlLiSRDR+DN00a2paweobc4zkqYP/0gU+d4jODOhQvZ9DFAsE4kQZpsXOzNfRrTeD+fWUnMFtAcuP5wfzEsz9Gm/ENqSW/sf0JQaTCWAxHmqaMpauPUZXNWEiuzRhMaXSDRmD4nV1DOcTqvDj5BtUWWdnJQV+by4VjVceI6gYuC5E3R+m4p6QG4wiASRPe+mpGacCousLwjL6a6Zx+iA2MXhQiPM6WjQTWIWA3TKwu105/ojzopukCuQ7OU8pfwSzz8XBB1dfrQ1kOzlPKX8Es8/FwQdXX60Nb+YHwc5536J89tvlGzFHGI=", "123456");
        System.out.println(licenseIsError);

        if (licence.equals(licenceStr)) {
            System.out.println("OK");
        }

        //FA814E8C4675AD8615D20A39100BB22A2024A1225_ FA814E8C4675AD8615D20A39100BB22A_ 120210922
        //389333BCF0FD8C355C3CA5EB80026320
        String YYYYMMddStr = identifyMd5.toUpperCase() + getYear() + decryptedStrings[0] + "_ " + decryptedStrings[1] + "_ " + decryptedStrings[2] + "20210922";
        System.out.println("年月日字符串：");
        System.out.println(YYYYMMddStr);
        String licenceYYYYMMddStr = md5(YYYYMMddStr).toUpperCase();
        System.out.println("注册码：");
        System.out.println(licenceYYYYMMddStr);

        List<String> licenceList = new ArrayList<>();
        licenceList.add(licence);


        System.out.println("Hello World!");
    }

    private static String getYear() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy");
        return format.format(new Date());
    }

    private static String getIdentify() {
        return getMacAddress() + getCPUSerial() + getBoardSerial();
    }

    private static String getCPUSerial() {
        String cpuSerial = "CPUID000";

        try {
            Process process = Runtime.getRuntime().exec(new String[]{"wmic", "cpu", "get", "ProcessorId"});
            process.getOutputStream().close();
            Scanner scanner = new Scanner(process.getInputStream());
            scanner.next();
            cpuSerial = scanner.next();
        } catch (Exception ignored) {
        }

        return cpuSerial;
    }

    private static String getBoardSerial() {
        StringBuilder boardSerial = new StringBuilder("ZBXLH000");

        try {
            File file = File.createTempFile("realhowto", ".vbs");
            file.deleteOnExit();
            FileWriter writer = new FileWriter(file);
            String script = "Set objWMIService = GetObject(\"winmgmts:\\\\.\\root\\cimv2\")\nSet colItems = objWMIService.ExecQuery _ \n   (\"Select * from Win32_BaseBoard\") \nFor Each objItem in colItems \n    Wscript.Echo objItem.SerialNumber \n    exit for  ' do the first cpu only! \nNext \n";
            writer.write(script);
            writer.close();
            Process process = Runtime.getRuntime().exec("cscript //NoLogo " + file.getPath());

            BufferedReader reader;
            String lineStr;
            reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            while ((lineStr = reader.readLine()) != null) {
                boardSerial.append(lineStr);
            }

            reader.close();
        } catch (Exception ignored) {
        }

        return boardSerial.toString().trim();
    }

    private static String getHostName() {
        return System.getProperty("os.name").toLowerCase();
    }

    private static String getMacAddress() {
        String macAddress;
        String hostName = getHostName();
        if (hostName.startsWith("windows")) {
            macAddress = getMacAddressForWindows();
        } else {
            macAddress = getMacAddressForOther();
        }
        return macAddress;
    }

    private static String getMacAddressForWindows() {
        String mac = "";

        byte[] addr;
        try {
            InetAddress host = InetAddress.getLocalHost();
            addr = NetworkInterface.getByInetAddress(host).getHardwareAddress();
        } catch (Exception ignored) {
            return null;
        }

        StringBuilder builder = new StringBuilder();
        if (addr == null) {
            return null;
        } else {
            for (int i = 0; i < addr.length; ++i) {
                if (i != 0) {
                    builder.append("-");
                }

                int b = addr[i] & 255;
                String s = Integer.toHexString(b);
                if (s.length() == 1) {
                    builder.append("0").append(s);
                } else {
                    builder.append(s);
                }
            }

            mac = builder.toString().toUpperCase();
            if (mac.isEmpty()) {
                return null;
            } else {
                return mac;
            }
        }
    }

    private static String getMacAddressForOther() {
        String mac = "";

        try {
            Enumeration interfaces = NetworkInterface.getNetworkInterfaces();

            while (true) {
                byte[] addr;
                do {
                    if (!interfaces.hasMoreElements()) {
                        return mac;
                    }

                    addr = ((NetworkInterface) interfaces.nextElement()).getHardwareAddress();
                } while (addr == null);

                StringBuilder builder = new StringBuilder();
                byte[] tempAddr = addr;
                int length = addr.length;

                for (int i = 0; i < length; ++i) {
                    byte b = tempAddr[i];
                    builder.append(paddleLeft(b));
                    builder.append("-");
                }

                builder.deleteCharAt(builder.length() - 1);
                mac = builder.toString().toUpperCase();
            }
        } catch (Exception ignore) {
            return mac;
        }
    }

    private static String paddleLeft(byte b) {
        String s = "000000" + Integer.toHexString(b);
        return s.substring(s.length() - 2);
    }


    private static String md5(String decryptedString) {
        MessageDigest digest = null;
        try {
            digest = MessageDigest.getInstance("MD5");
            digest.reset();
            digest.update(decryptedString.getBytes(StandardCharsets.UTF_8));
        } catch (NoSuchAlgorithmException ignored) {
        }
        byte[] encryptedData = digest.digest();
        StringBuilder stringBuffer = new StringBuilder();

        for (byte encryptedByte : encryptedData) {
            if (Integer.toHexString(255 & encryptedByte).length() == 1) {
                stringBuffer.append("0").append(Integer.toHexString(255 & encryptedByte));
            } else {
                stringBuffer.append(Integer.toHexString(255 & encryptedByte));
            }
        }
        return stringBuffer.toString();
    }

    private static String decryptRsa(String privateKeyString, String encryptedString) {
        try {
            byte[] encryptedData = Base64.getDecoder().decode(encryptedString);
            byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(privateKeyBytes);
            PublicKey privateKey = keyFactory.generatePublic(keySpec);
            Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] buf = cipher.doFinal(encryptedData);
            return new String(buf, StandardCharsets.UTF_8);
        } catch (Exception e) {
            return null;
        }
    }

    private static String decryptAes(String encryptedString, String privateKeyString) throws Exception {
        byte[] encryptedData = Base64.getDecoder().decode(encryptedString);
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        secureRandom.setSeed(privateKeyString.getBytes());
        keyGenerator.init(128, secureRandom);
        Cipher cipher = Cipher.getInstance("AES");
        SecretKeySpec keySpec = new SecretKeySpec(keyGenerator.generateKey().getEncoded(), "AES");
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        byte[] buf = cipher.doFinal(encryptedData);
        return new String(buf, StandardCharsets.UTF_8);
    }
}
